package com.fastloan.mgt.model.service.impl;

import com.fastloan.common.BasicServiceImpl;
import com.fastloan.mgt.application.base.enums.ApplicationStatusEnum;
import com.fastloan.mgt.application.base.model.Application;
import com.fastloan.mgt.application.base.service.ApplicationService;
import com.fastloan.mgt.model.annotation.ModelClass;
import com.fastloan.mgt.model.dao.ApplicationModelMapper;
import com.fastloan.mgt.model.model.ApplicationModel;
import com.fastloan.mgt.model.model.Model;
import com.fastloan.mgt.model.service.GeneratorModelStrategy;
import com.fastloan.mgt.model.service.ModelCalculateService;
import com.fastloan.mgt.model.uitl.ModelUtil;
import com.fastloan.mgt.processcontrol.base.annotation.FunctionHandlerClass;
import com.fastloan.mgt.processcontrol.base.annotation.FunctionHandlerMethod;
import com.fastloan.mgt.processcontrol.base.model.ProcessSession;
import com.fastloan.mgt.processcontrol.base.service.ProcessDispatcher;
import com.fastloan.mgt.processcontrol.base.util.BeanFactoryUtil;
import com.fastloan.mgt.product.basics.model.Product;
import com.fastloan.mgt.product.basics.service.ProductService;
import com.fastloan.mgt.product.flow.enums.ProductFunctionGroup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 模型计算Service
 *
 * @author yanwe
 *         createTime 2017-02-2017/2/14 13:43
 */
@Service
@FunctionHandlerClass(processName = "模型计算",bmpIds = {ProductFunctionGroup.GROUP_ONE})
public class ModelCalculateServiceImpl extends BasicServiceImpl<ApplicationModel> implements ModelCalculateService {

    @Autowired
    private ApplicationModelMapper applicationModelMapper;

    @Autowired
    private ApplicationService applicationService;

    @Autowired
    private ProductService productService;

    public static final Integer PASS = 1;

    public static final Integer NO_PASS = 0;

    @Override
    @FunctionHandlerMethod
    public void calculateInProcess(String processId) {
        ProcessSession processSession = ProcessDispatcher.getProcessSession(processId);
        String applicationId = processSession.getAttribute("applicationId", String.class);
        applicationService.modifyApplicationStatus(applicationId,ApplicationStatusEnum.MODEL_EVALUATE_ING);
        calculate(applicationId);
    }

    @Override
    public void calculate(String applicationId){
        Application application = applicationService.selectByPrimaryKey(applicationId);
        Product product = productService.selectByPrimaryKey(application.getProductId());
        Optional<Model> modelOptional = choiceModel(product.getModelType());
        if (!modelOptional.isPresent()){
            String errorMsg = "进件:"+applicationId+"模型:"+product.getModelType()+"不存在";
            log.error(errorMsg);
            throw new RuntimeException(errorMsg);
        }
        Model model = modelOptional.get();
        model.getModelHandler().calculate(applicationId,this::saveModelResult);
    }

    @Override
    public <T extends GeneratorModelStrategy> boolean isHaveModel(String applicationId, Class<T> modelStrategyClass){
        Application application = applicationService.selectByPrimaryKey(applicationId);
        Product product = productService.selectByPrimaryKey(application.getProductId());
        return product.getModelType().equals(ModelUtil.convertModel(
                BeanFactoryUtil.getBeansOfType(modelStrategyClass)).getModelId());
    }

    @Override
    public List<Model> getAllModel(){
        Map<String, GeneratorModelStrategy> modelStrategyMap = BeanFactoryUtil
                .getBeansOfType(GeneratorModelStrategy.class);
        return modelStrategyMap.entrySet().stream()
                .map(Map.Entry::getValue)
                .map(GeneratorModelStrategy::getModelInfo)
                .collect(Collectors.toList());
    }

    @Override
    public List<ApplicationModel> getModelResult(String applicationId){
        ApplicationModel applicationModel = new ApplicationModel();
        applicationModel.setApplicationId(applicationId);
        return applicationModelMapper.select(applicationModel);
    }

    @Override
    public ApplicationModel getLastModelResult(String applicationId) {
        return getModelResult(applicationId).stream()
                .sorted(Comparator.comparing(ApplicationModel::getCreateTime).reversed())
                .findFirst().orElse(null);
    }

    @Override
    public void saveModelResult(ApplicationModel applicationModel){
        if (applicationModel.getApplicationId() == null){
            return;
        }
        Application application = applicationService.selectByPrimaryKey(applicationModel.getApplicationId());
        if (application == null){
            return;
        }
        saveModel(applicationModel);
        boolean canNext = PASS.equals(applicationModel.getPass());
        if (!canNext) {
            //未通过
            applicationService.modifyApplicationStatus(applicationModel.getApplicationId()
                    ,ApplicationStatusEnum.MODEL_REJECT);
        }
        String processId = application.getProcessId();
        ProcessDispatcher.executeEnd(processId, canNext);
    }

    @Override
    public Optional<Model> choiceModel(int modelId) {
        Map<String, GeneratorModelStrategy> modelStrategyMap = BeanFactoryUtil
                .getBeansOfType(GeneratorModelStrategy.class);
        return modelStrategyMap.entrySet().stream().map(Map.Entry::getValue)
                .map(GeneratorModelStrategy::getModelInfo)
                .filter(model -> model.getModelId().equals(modelId))
                .findFirst();
    }

    private void saveModel(ApplicationModel applicationModel){
        ApplicationModel criteria = new ApplicationModel();
        criteria.setApplicationId(applicationModel.getApplicationId());
        applicationModelMapper.delete(criteria);
        applicationModelMapper.insertSelective(applicationModel);
    }
}
